package com.zy.blog.common.util;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zy.blog.common.enums.ConditionEnum;
import com.zy.blog.common.param.ConditionParam;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * Author: zy
 * Description: 高阶查询工具类
 * Date: 2020/5/20
 */
public final class WrappersUtil {
    /*
     * 禁止实例化
     */
    private WrappersUtil() {
        throw new AssertionError();
    }

    /**
     * 构建高阶查询条件构造器
     * @param queryConditions: 高阶查询条件
     * @param entityClass: 实体类class
     * @return QueryWrapper:
     */
    public static <T> QueryWrapper<T> query(List<ConditionParam> queryConditions, Class<?> entityClass){
        //构建条件构造器
        QueryWrapper<T> wrappers = Wrappers.query();
        if(queryConditions == null){
            queryConditions = new ArrayList<>();
        }

        //构建查询条件
        build(queryConditions, wrappers,entityClass);

        return wrappers;
    }


    /**
     * 构建高阶查询条件构造器 支持lambda表达式
     * @param queryConditions: 高阶查询条件
     * @param entityClass: 实体类class
     * @return LambdaQueryWrapper:
     */
    public static <T> LambdaQueryWrapper<T> lambdaQuery(List<ConditionParam> queryConditions, Class<?> entityClass){
        return WrappersUtil.<T>query(queryConditions,entityClass).lambda();
    }

    /**
     * 构建高阶更新条件构造器
     * @param conditions: 高阶查询条件
     * @param entityClass: 实体类class
     * @return UpdateWrapper:
     */
    public static <T> UpdateWrapper<T> update(List<ConditionParam> conditions, Class<?> entityClass){
        //构建条件构造器
        UpdateWrapper<T> wrappers = Wrappers.update();
        if(conditions == null){
            conditions = new ArrayList<>();
        }
        //构建查询条件
        build(conditions, wrappers,entityClass);

        return wrappers;
    }

    /**
     * 构建高阶更新条件构造器  支持lambda表达式
     * @param conditions: 高阶查询条件
     * @param entityClass: 实体类class
     * @return UpdateWrapper:
     */
    public static <T> LambdaUpdateWrapper<T> lambdaUpdate(List<ConditionParam> conditions, Class<?> entityClass){
        return WrappersUtil.<T>update(conditions,entityClass).lambda();
    }


    /**
     * 构建查询条件
     * @param conditions: 查询条件
     * @param wrappers:
     * @param entityClass: 实体类class
     * @return void:
     */
    private static <T,C extends AbstractWrapper<T, String, C>> void build(List<ConditionParam> conditions,
                                                                          AbstractWrapper<T,String,C> wrappers, Class<?> entityClass) {
        //判断是否存在order by条件、如果不存在、自动追加
        boolean existOrderBy = false;

        //拼接高级查询条件
        for(ConditionParam queryCondition:conditions){
            //拼接sql
            boolean isContinue = false;
            if (queryCondition.getCondition() == ConditionEnum.APPLY && StrUtil.isNotBlank(queryCondition.getValue())) {
                //防止sql注入 替换特殊字符
                wrappers.nested(i->i.apply(queryCondition.getValue().replace("--","")));
                isContinue = true;
            }

            // 获取字段名
            String fieldName = queryCondition.getField();

            //获取泛型的class指定字段 如果指定字段不存在
            if(StrUtil.isBlank(fieldName) ){
                isContinue = true;
            }

            // 获取entityClass类对应的字段
            Field field = ReflectUtil.getField(entityClass,fieldName);
            if(field == null){
                isContinue=true;
            }

            if(isContinue){
                continue;
            }

            // 获取数据表字段名
            String tableFieldName = getTableFieldName(field);

            switch (queryCondition.getCondition()){
                case EQ:
                    wrappers.eq(tableFieldName,queryCondition.getValue());
                    break;
                case NE:
                    wrappers.ne(tableFieldName,queryCondition.getValue());
                    break;
                case IN:
                    wrappers.in(StringUtils.isNotBlank(queryCondition.getValue()), tableFieldName, queryCondition.getValue().split(","));
                    break;
                case NOT_IN:
                    wrappers.notIn(StringUtils.isNotBlank(queryCondition.getValue()), tableFieldName, queryCondition.getValue().split(","));
                    break;
                case GT:
                    wrappers.gt(tableFieldName,queryCondition.getValue());
                    break;
                case GE:
                    wrappers.ge(tableFieldName,queryCondition.getValue());
                    break;
                case LE:
                    wrappers.le(tableFieldName,queryCondition.getValue());
                    break;
                case LIKE:
                    wrappers.like(tableFieldName,queryCondition.getValue());
                    break;
                case NOT_LIKE:
                    wrappers.notLike(tableFieldName,queryCondition.getValue());
                    break;
                case LIKE_LEFT:
                    wrappers.likeLeft(tableFieldName,queryCondition.getValue());
                    break;
                case LIKE_RIGHT:
                    wrappers.likeRight(tableFieldName,queryCondition.getValue());
                    break;
                case IS_NULL:
                    wrappers.isNull(tableFieldName);
                    break;
                case IS_NOT_NULL:
                    wrappers.isNotNull(tableFieldName);
                    break;
                case ORDER_BY_ASC:
                    wrappers.orderByAsc(tableFieldName);
                    existOrderBy = true;
                    break;
                case ORDER_BY_DESC:
                    wrappers.orderByDesc(tableFieldName);
                    existOrderBy = true;
                    break;
                default:
                    break;
            }
        }

        //默认根据数据表id  order by排序
        if(wrappers instanceof QueryWrapper && !existOrderBy) {
            Field field = ReflectUtil.getField(entityClass, "createTime");
            if (field == null) {
                field = ReflectUtil.getField(entityClass, "id");
            }

            if(field != null) {
                wrappers.orderByDesc(getTableFieldName(field));
            }
        }
    }

    /**
     * 查找实体类entityClass fileName字段对应的数据表字段名
     */
    private static String getTableFieldName(Field field){
        /* 获取注解属性，自定义字段 */
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null && StrUtil.isNotBlank(tableField.value())) {
            // 修改为表对应的字段
            return tableField.value();
        } else {
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId != null && StrUtil.isNotBlank(tableId.value())) {
                // 修改为表对应的字段
                return tableId.value();
            }
            return field.getName().replaceAll("[A-Z]", "_$0").toLowerCase();
        }
    }
}
